import { message as AntMessage } from 'antd';
import axios, { AxiosError, AxiosInstance, AxiosRequestConfig, AxiosResponse } from 'axios';
import { lpLocalStorage } from './localStorage';

import { batch, Observable, observable } from '@legendapp/state';



export class GlobalProcessor {
  // 用户信息
  userInfo: any;

  currTenant:any;

  appId: Observable<string>;

  /**
   * 是否显示无权页面
   */
  showAuthPage: Observable<boolean>;

  /**
   * 是否是系统管理员
   */
  isAdmin: Observable<boolean>;

  /**
   * 是否是应用管理员
   */
  isAppAdmin: Observable<boolean>;

  /**
   * 资源项
   */
  resources: any;

  constructor() {
    this.userInfo = observable<any>({} as any);
    this.currTenant = observable<any>({} as any);
    this.appId = observable('');
    this.showAuthPage = observable(false);
    this.isAdmin = observable(false);
    this.isAppAdmin = observable(false);
    this.resources = observable({} as any);
    this.init();
  }

  private init = async () => {
    this.listeners();
  };
  setUserInfo = (
    userInfo: any,
    {
      tenantId,
      appId,
    }: {
      tenantId?: string;
      appId?: string;
    }
  ) => {
    const currTenantId =
      tenantId || userInfo?.app?.tenantId || lpLocalStorage.get('tenant_id');
    let tenant = currTenantId && userInfo?.tenantList?.find((f) => f.id == currTenantId);
    if (!tenant) {
      tenant = userInfo?.tenantList?.[0];
    }
    // 设置租户信息
    this.setCurrTenant(tenant);
    this.userInfo.set(userInfo);
  };

  setCurrTenant = (tenant: any) => {
    if (tenant) {
      lpLocalStorage.add('tenant_id', tenant?.id);
      this.currTenant.set(tenant);
    }
  };

  setAppId = (appId: string) => {
    this.appId.set(appId);
  };

  setUserInfoApp = (app: any) => {
    this.userInfo.app.set(app);
  };

  /**
   * 设置资源项目
   * @param resources
   */
  setResources = (resources: any) => {
    this.resources.set(resources);
  };

  /**
   * 变更admin权限
   */
  private changeAdminPerm = () => {
    const userInfo = this.userInfo.peek();
    const appId = this.appId.peek();
    batch(() => {
      this.isAdmin.set(userInfo?.isAdmin);
      if (appId) {
        const currAppPerm = userInfo?.appPerm?.[appId!];
        this.isAppAdmin.set(userInfo?.isAdmin || currAppPerm?.rights?.length > 0);
      }
    });
  };

  /**
   * 开启监听器
   */
  private listeners = () => {
    this.userInfo.onChange((changeData) => {
      this.changeAdminPerm();
    });

    this.appId.onChange((changeData) => {
      this.changeAdminPerm();
    });
  };
}


// @ts-ignore
const processor = window._tmpGp || window?.parent?._tmpGp;

if (!processor) {
  // @ts-ignore
  window._tmpGp = new GlobalProcessor();
}
// @ts-ignore
const globalProcessor = window._tmpGp || window?.parent?._tmpGp;

/**
 * 获取appid
 * @returns
 */
export function getAppId() {
  return globalProcessor.appId.peek(); // lpLocalStorage.get(ELocationStorageKey.appId) || '';
}

export function getTenantId() {
  return (
    globalProcessor.currTenant?.id?.peek() || lpLocalStorage.get('tenant_id') || ''
  );
}

let umiHistory: any = {};

export const setUmiHistory = (history: any) => {
  umiHistory = history;
};

const push = (to: string, state?: any) => {
  umiHistory?.push(to, state);
};

const replace = (to: string, state?: any) => {
  umiHistory?.replace(to, state);
};

const go = (index: number) => {
  umiHistory?.go(index);
};

export const history = { push, replace, go };
export default history;


export const clearUserInfo = () => {
  lpLocalStorage.remove('user_token');
  lpLocalStorage.remove('user_info');
};

export const goLogin = (isRedirectUrl?: boolean) => {
  clearUserInfo();
  const redirectUrl = encodeURIComponent(window.location.href);
  let url = '/login';

  // 是否加了重定向的url
  if (isRedirectUrl) {
    url += '?redirect_url=' + redirectUrl;
  }

  history.push(url);
};

export const goNoAuth = () => {
  globalProcessor?.showAuthPage.set(true);
};


export const getRequestHeader = () => {
  const headers: any = {};
  const appId = getAppId(); // lpLocalStorage.get(ELocationStorageKey.appId);

  // 处理app
  if (appId) {
    headers['applicationId'] = getAppId();
  }

  // 处理token
  const token = lpLocalStorage.get('user_token');
  if (token) {
    headers['token'] = token;
  }

  // 处理tenant
  const tenantId = getTenantId(); // lpLocalStorage.get(ELocationStorageKey.tenantId);
  if (tenantId) {
    headers['tenantId'] = tenantId;
  }

  return headers;
};

const service: AxiosInstance = axios.create({
  baseURL: '/api',
  timeout: 0,
  headers: {},
});

service.interceptors.request.use(
  (config) => {
    const requestHeaders = getRequestHeader();

    if (requestHeaders) {
      Object.keys(requestHeaders).forEach((key) => {
        config.headers[key] = requestHeaders[key];
      });
    }
    return config;
  },
  () => { }
);

/* 响应拦截器 */
service.interceptors.response.use(
  (response: AxiosResponse) => {
    const { code, message, msg, data } = response.data;
    if (code === '0000' || code === '200' || code === 200) {
      return data;
    }

    // 用户未登录
    if (code === '208') {
      goLogin(true);
      return Promise.reject(message); // TODO 这里可以不用拦截，直接出提示
    }
    const errorMessage = msg || message || '服务端出错了！';
    console.error(`SERVER_ERROR:${errorMessage}`);
    AntMessage.error(errorMessage);
    return Promise.reject(message);
  },
  (error: AxiosError) => {
    // 处理 HTTP 网络错误
    let message = '';
    // HTTP 状态码
    const status = error.response?.status;
    switch (status) {
      case 401:
        message = 'token 失效，请重新登录';
        goLogin(true);
        return;
      // 这里可以触发退出的 action
      case 403:
        message = '拒绝访问';
        // 去未授权路由
        goNoAuth();
        return;
        break;
      case 404:
        message = '请求地址错误';
        break;
      case 500:
        message = '服务器故障';
        break;
      default:
        message = '网络连接故障';
    }
    AntMessage.error(message);
    return Promise.reject(error);
  }
);

/* 导出封装的请求方法 */
export const http = {
  get<T = any>(url: string, config?: AxiosRequestConfig): Promise<T> {
    return service.get(url, config);
  },

  post<T = any>(url: string, data?: object, config?: AxiosRequestConfig): Promise<T> {
    return service.post(url, data, config);
  },

  upload<T = any>(url: string, data?: object, config?: AxiosRequestConfig): Promise<T> {
    const headers = { 'Content-Type': 'multipart/form-data' };
    const newConfig = { ...config, headers };
    return service.post(url, data, newConfig);
  },

  put<T = any>(url: string, data?: object, config?: AxiosRequestConfig): Promise<T> {
    return service.put(url, data, config);
  },

  delete<T = any>(url: string, config?: AxiosRequestConfig): Promise<T> {
    return service.delete(url, config);
  },
};

export { http as Request };
